package com.apes.framework.plugin.esb.processor.jpa;

import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.jpa.spec.Sorts;
import com.apes.framework.plugin.esb.api.Request;
import com.apes.framework.plugin.esb.processor.AbstractChainProcessor;
import com.apes.framework.util.JpaUtil;
import com.apes.framework.util.MapUtil;
import lombok.Data;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Map;

/**
 * 功能：FindOneProcessor
 *
 * @author xul
 * @create 2018-07-11 9:42
 */
@Data
public class FindAllProcessor<T extends Request, R> extends AbstractChainProcessor<T, R> {

    private String repository = null;
    private String sort = null;
    private boolean paged = true;
    private int page = 0;
    private int size = 20;
    private boolean distinct = false;
    private String excludesFields = null;

    @Override
    protected R doProcess(T source) {
        if (StringUtils.isEmpty(this.repository)) throw new RuntimeException("repository 不允许为空！");
        // 额外增加外界配置分页的选项
        Map m = source.getMap();
        if ((m.get("paged") != null && (boolean) m.get("paged")) ||
                (m.get("paged") == null && paged)) {
            if (m.containsKey("page")) this.page = (int) m.get("page");
            if (m.containsKey("size")) this.size = (int) m.get("size");
        }

        Specification<T> spec = JpaDsl.build(source, distinct);
        CustomRepository repository = JpaUtil.getRepositoryByName(this.repository);
        Pageable pageable = getPageable(source);
        Object result;
        if (pageable != null) {
            result = repository.findAll(spec, pageable);
        } else {
            result = repository.findAll(spec);
        }
        if (StringUtils.hasText(excludesFields)) {
            result = MapUtil.mapped(result, excludesFields.split(","));
        }
        return (R) result;
    }

    private Pageable getPageable(T source) {
        Map m = source.getMap();
        if (!((m.get("paged") != null && (boolean) m.get("paged")) ||
                (m.get("paged") == null && paged))) return null;
        Sort sort = getSort();
        if (sort != null) return PageRequest.of(this.page, this.size, sort);
        return PageRequest.of(this.page, this.size);
    }

    private Sort getSort() {
        if (StringUtils.isEmpty(this.sort)) return null;
        String[] sorts = this.sort.split(",");
        Sorts.Builder builder = Sorts.builder();
        Arrays.stream(sorts).forEach(sort -> {
            String[] order = StringUtils.split(sort.trim(), " ");
            if (order.length == 1) {
                builder.asc(order[0].trim());
            } else {
                if (order[1].trim().equalsIgnoreCase("desc")) {
                    builder.desc(order[0].trim());
                } else {
                    builder.asc(order[0].trim());
                }
            }
        });
        if (builder.getOrders().isEmpty()) return null;
        return builder.build();
    }
}
